
package com.yadong.smarthome2.protocol2.wificlient;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

import android.util.Log;

import com.yadong.smarthome2.protocol2.RequestProtocol.Request;
import com.yadong.smarthome2.protocol2.ResultProtocol.Result;

public class SocketServerConnectionThread extends Thread {
    protected volatile boolean mStopRuning = false;
    protected volatile boolean mStopConnection = false;
    private Socket mConnectionSocket = null;
    private InputStream mObjectInputStream = null;
    private OutputStream mObjectOutputStream = null;
    private final String TAG;
    private boolean mConnected = false;
    private NewRequestListener mNewMessageListener = null;

    public SocketServerConnectionThread(String name) {
        super(name);
        TAG = name;
    }

    /**
     * Invoke when thread start. Override to change the running status Or other init things. like
     * create ServerSocket.
     */
    protected void initRunningArgument() {
        mStopRuning = false;
        mStopConnection = false;
    }

    /*
     * Invoke when thread done. for Server Thread need override to release the ServerSocket.
     */
    protected void releaseServerSocket() {
        releaseStream();
        if (mConnectionSocket != null) {
            try {
                mConnectionSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            mConnectionSocket = null;
        }
    }

    private void releaseStream() {
        if (mObjectInputStream != null) {
            try {
                mObjectInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            mObjectInputStream = null;
        }
        if (mObjectOutputStream != null) {
            try {
                mObjectOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            mObjectOutputStream = null;
        }
    }

    /**
     * Get the connection status
     * 
     * @return if connected true else false
     */
    public boolean isConnected() {
        return mConnected;
    }

    /**
     * Can use this function to send data to Client
     * 
     * @param o
     * @throws Exception
     */
    public void sendDataToClient(final Result result) throws Exception {
        new Thread(Thread.currentThread().getName() + "_send_data_thread") {
            @Override
            public void run() {
                try {
                    Log.v(TAG, "Data to send " + result + (mConnectionSocket != null)
                            + (mObjectOutputStream == null));
                    if (mConnected) {
                        if (mConnectionSocket != null && mObjectOutputStream == null) {
                            OutputStream outputStream = mConnectionSocket.getOutputStream();
                            mObjectOutputStream = outputStream;
                        }
                        result.writeDelimitedTo(mObjectOutputStream);
                        mObjectOutputStream.flush();
                    } else {
                        Log.e(TAG, "Socket do not connected");
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }

    /**
     * Just stop the connection, but don't exit the thread.
     */
    public void stopConnection() {
        mStopConnection = true;
    }

    /**
     * disconnected the connection, and exit the thread.
     */
    public void stopRuning() {
        mStopConnection = true;
        mStopRuning = true;
    }

    /**
     * Set the message receive listener
     * 
     * @param listener
     */
    public void setNewMessageReceiveListener(NewRequestListener listener) {
        mNewMessageListener = listener;
    }

    private Request getDataFromClient() throws Exception {
        Log.d(TAG, "start get message");
        if (mConnectionSocket != null && mObjectInputStream == null) {
            InputStream inputStream = mConnectionSocket.getInputStream();
            mObjectInputStream = inputStream;
        }
        //send a urgent package to ensure connection.
        mConnectionSocket.sendUrgentData(0);
        Request request = Request.parseDelimitedFrom(mObjectInputStream);
        return request;
    }

    public void run() {
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(10081);
            while (!mStopRuning) {
                // We just need one connection.So if connected , we will not
                // continue to accept new socket
                mConnectionSocket = serverSocket.accept();
                mConnected = true;
                if (mConnectionSocket == null) {
                    Log.e(TAG, " null socket");
                    return;
                }
                while (!mStopConnection) {
                    try {
                        Request in = getDataFromClient();
                        if (in != null) {
                            Log.v(TAG, "get message:" + in);
                            if ("stop".equals(in)) {
                                mStopConnection = true;
                            }
                            if (mNewMessageListener != null) {
                                mNewMessageListener.onNewMessageReceived(getName(), in);
                            }
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        Log.e(TAG, "connection disconnected ... try receive another");
                        releaseStream();
                        break;
                    }
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            Log.e(TAG, "bey bey!");
            releaseStream();
            releaseServerSocket();
            if (serverSocket != null) {
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}
